#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
批量实验ExecuteScript
按顺序ExecuteMultiple实验方案，并Generate汇总报告
"""

import os
import sys
import json
import argparse
import subprocess
from pathlib import Path
from datetime import datetime
from typing import List, Dict, Any


def run_single_experiment(scheme_file: str, verbose: bool = False) -> Dict[str, Any]:
    """
    ExecuteSingle实验方案
    
    Args:
        scheme_file: 方案FilePath
        verbose: YesNoDetailedOutput
        
    Returns:
        实验ResultDictionary
    """
    result = {
        'scheme_file': scheme_file,
        'scheme_name': Path(scheme_file).stem,
        'success': False,
        'start_time': datetime.now().isoformat(),
        'end_time': None,
        'duration': None,
        'error': None
    }
    
    try:
        # Read方案名称
        with open(scheme_file, 'r', encoding='utf-8') as f:
            config = json.load(f)
            result['experiment_name'] = config.get('experiment_name', 'Unknown')
        
        # Execute实验
        cmd = ['python', 'run_experiment.py', scheme_file]
        if verbose:
            cmd.append('--verbose')
        
        print(f"\n{'='*70}")
        print(f"Execute实验: {result['experiment_name']}")
        print(f"方案File: {scheme_file}")
        print(f"{'='*70}\n")
        
        start = datetime.now()
        proc_result = subprocess.run(
            cmd,
            cwd=Path(__file__).parent,
            capture_output=not verbose,
            text=True,
            timeout=14400  # 4小时超时
        )
        
        end = datetime.now()
        result['end_time'] = end.isoformat()
        result['duration'] = (end - start).total_seconds()
        
        if proc_result.returncode == 0:
            result['success'] = True
            print(f"\n实验SuccessCompleted (耗时: {result['duration']:.1f}秒)")
        else:
            result['error'] = f"Return码: {proc_result.returncode}"
            print(f"\n实验Failed: {result['error']}")
            if not verbose and proc_result.stderr:
                print(f"ErrorInformation: {proc_result.stderr[:500]}")
        
    except subprocess.TimeoutExpired:
        result['error'] = 'Execute超时'
        result['end_time'] = datetime.now().isoformat()
        print(f"\n实验超时")
    except Exception as e:
        result['error'] = str(e)
        result['end_time'] = datetime.now().isoformat()
        print(f"\n实验异常: {e}")
    
    return result


def generate_batch_summary(results: List[Dict[str, Any]], output_file: str):
    """
    Generate批量实验汇总报告
    
    Args:
        results: 实验ResultList
        output_file: Output filePath
    """
    summary = {
        'batch_execution_time': datetime.now().isoformat(),
        'total_experiments': len(results),
        'successful_experiments': sum(1 for r in results if r['success']),
        'failed_experiments': sum(1 for r in results if not r['success']),
        'total_duration': sum(r.get('duration', 0) for r in results if r.get('duration')),
        'results': results
    }
    
    # SaveJSON报告
    with open(output_file, 'w', encoding='utf-8') as f:
        json.dump(summary, f, indent=2, ensure_ascii=False)
    
    # Print汇总
    print(f"\n{'='*70}")
    print(f"  批量实验汇总")
    print(f"{'='*70}")
    print(f"总实验数: {summary['total_experiments']}")
    print(f"Success: {summary['successful_experiments']}")
    print(f"Failed: {summary['failed_experiments']}")
    print(f"总耗时: {summary['total_duration']:.1f}秒 ({summary['total_duration']/60:.1f}分钟)")
    
    print(f"\nDetailedResult:")
    for i, result in enumerate(results, 1):
        status = "Success" if result['success'] else "Failed"
        duration = f"{result.get('duration', 0):.1f}s" if result.get('duration') else "N/A"
        print(f"  {i}. {result.get('experiment_name', result['scheme_name'])}")
        print(f"     Status: {status}, 耗时: {duration}")
        if not result['success'] and result.get('error'):
            print(f"     Error: {result['error']}")
    
    print(f"\n批量汇总报告: {output_file}")
    print(f"{'='*70}\n")


def main():
    parser = argparse.ArgumentParser(
        description='批量ExecuteMultipleSide-Channel Attack实验方案',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Example:
  # ExecuteschemeDirectory下的All方案
  python run_batch_experiments.py --all
  
  # Execute指定的Multiple方案
  python run_batch_experiments.py scheme/aes_*.json
  
  # Execute并DisplayDetailedOutput
  python run_batch_experiments.py --all --verbose
  
  # 指定Output报告Path
  python run_batch_experiments.py --all --output results/batch_summary.json
        """)
    
    parser.add_argument('schemes', nargs='*',
                       help='实验方案FileList（Support通配符）')
    
    parser.add_argument('--all', '-a', action='store_true',
                       help='ExecuteschemeDirectory下的All方案')
    
    parser.add_argument('--verbose', '-v', action='store_true',
                       help='DisplayDetailedOutput')
    
    parser.add_argument('--output', '-o', type=str, 
                       default='results/batch_summary.json',
                       help='批量汇总报告OutputPath (Default: results/batch_summary.json)')
    
    parser.add_argument('--continue-on-error', action='store_true',
                       help='遇ToErrorContinueExecute后续实验')
    
    args = parser.parse_args()
    
    # 获取方案List
    scheme_files = []
    
    if args.all:
        scheme_dir = Path(__file__).parent / 'scheme'
        if scheme_dir.exists():
            scheme_files = sorted(scheme_dir.glob('*.json'))
    elif args.schemes:
        for pattern in args.schemes:
            scheme_files.extend(Path().glob(pattern))
    else:
        parser.print_help()
        return 1
    
    if not scheme_files:
        print("Error: 没Has找To实验方案File")
        return 1
    
    print(f"\n准备Execute {len(scheme_files)} 个实验方案:")
    for i, sf in enumerate(scheme_files, 1):
        print(f"  {i}. {sf}")
    
    # Execute实验
    results = []
    for i, scheme_file in enumerate(scheme_files, 1):
        print(f"\n{'#'*70}")
        print(f"# 批量实验进度: {i}/{len(scheme_files)}")
        print(f"{'#'*70}")
        
        result = run_single_experiment(str(scheme_file), verbose=args.verbose)
        results.append(result)
        
        # CheckYesNoContinue
        if not result['success'] and not args.continue_on_error:
            print(f"\n实验Failed，停止Execute后续实验")
            break
    
    # Generate汇总报告
    output_path = Path(args.output)
    output_path.parent.mkdir(parents=True, exist_ok=True)
    generate_batch_summary(results, str(output_path))
    
    # ReturnStatus
    failed_count = sum(1 for r in results if not r['success'])
    return 0 if failed_count == 0 else 1


if __name__ == '__main__':
    sys.exit(main())
